(1) 访问器属性
var book={};
Object.defineProperties(book,{
_year:{
writable:true,
value:2014
}
})
/*以上的Object.defineProperties可以给book对象的加属性以及以及对属性的操作等*/
//当然,也可以读取属性的特性。
var descriptor=Object.getOwnPropertyDescriptor(book,"_year");
alert(descriptor.value); //2014
alert(descriptor.configurable); //false
(2) 在对象和原型中查找属性或者方法的顺序。
如果按照字面意思来理解,那
么 prototype 就是通过调用构造函数而创建的那个对象实例的原型对象。使用原型对象的好处是可以
让所有对象实例共享它所包含的属性和方法。
.hasOwnProperty方法可以用来检查某个属性在实例中还是原型中。
同时使用 hasOwnProperty()方法和 in 操作符,就可以确定该属性到底是存在于对象中,还是存在于
原型中,如下所示。
//这个函数实现认识某个属性在不在原型中,在的话,返回ture,否则返回false;
function hasPrototypeProperty(object, name) {
return !object.hasOwnProperty(name) && (name in object);
}
function Person() {
}
Person.prototype.name = "nihao";
var person = new Person();
alert(hasPrototypeProperty(person, "name")); //ture,表明name在原型中。
person.name = "goobye";
alert(hasPrototypeProperty(person, "name")); //false,不在原型中
(3)组合使用构造函数和原型模式
创建自定义类型的最常见方式,就是组合使用构造函数模式与原型模式。构造函数模式用于定义实
例属性,而原型模式用于定义方法和共享的属性。结果,每个实例都会有自己的一份实例属性的副本,
但同时又共享着对方法的引用,最大限度地节省了内存。另外,这种混成模式还支持向构造函数传递参
数;可谓是集两种模式之长。下面的代码重写了前面的例子。
/*构造函数用于实例化属性*/
function Person(name, age, job) {
this.name = name;
this.age = age;
this.job = job;
this.friends = ['nihao', "goobye"];
}
/*原型模式用于定义方法和共享的属性*/
Person.prototype = {
constructor: Person,
sayName: function () {
alert(this.name);
}
}
var person1 = new Person("nihao", 29, "software Engineer")
alert(person1.name);//nihao
(4) 原型链
- 子类型有时候需要重写超类型中的某个方法,或者需要添加超类型中不存在的某个方法。但不管怎
样,给原型添加方法的代码一定要放在替换原型的语句之后。
function SuperType() {
this.property = true;
}
SuperType.prototype.getSuperValue = function () {
return this.property;
}
function SubType() {
this.subproperty = false;
}
//继承实现
SubType.prototype = new SuperType();
//添加新方法
SubType.prototype.getSubValue = function () {
return his.subproperty;
}
//重写超类型方法
SubType.prototype.getSuperValue = function () {
return false;
}
var instanc = new SubType();
alert(instanc.getSuperValue()); //false
(5) 原型继承的问题以及解决
它的问题就是当一个子类继承父类的时候,当定义子类对象时。子类某一个对象对父类中属性或者方法的改动都会反映到子类的其他对象中,
因为父类成了子类定义对象的原型。其他对象使用后也会有相应改变。那么可以使用借用构造函数来解决。
借用构造函数
function SuperType() {
this.colors = ["red", "blue", "green"];
}
function SubType() {
//继承了Suptype
SuperType.call(this);
}
var instance1 = new SubType();
instance1.colors.push("black");//"red,blue,green,black"
alert(instance1.colors);
var instance2 = new SubType();
alert(instance2.colors); //"red,blue,green" ,现在每个子类对象就保持了自己对父类的最初属性了。
(6) 小结
ECMAScript 支持面向对象(OO)编程,但不使用类或者接口。对象可以在代码执行过程中创建和 增强,因此具有动态性而非严格定义的实体。在没有类的情况下,可以采用下列模式创建对象。 1 工厂模式,使用简单的函数创建对象,为对象添加属性和方法,然后返回对象。这个模式后来 被构造函数模式所取代。 2 构造函数模式,可以创建自定义引用类型,可以像创建内置对象实例一样使用 new 操作符。不 过,构造函数模式也有缺点,即它的每个成员都无法得到复用,包括函数。由于函数可以不局 限于任何对象(即与对象具有松散耦合的特点),因此没有理由不在多个对象间共享函数。 3 原型模式,使用构造函数的 prototype 属性来指定那些应该共享的属性和方法。组合使用构造 函数模式和原型模式时,使用构造函数定义实例属性,而使用原型定义共享的属性和方法。 JavaScript 主要通过原型链实现继承。原型链的构建是通过将一个类型的实例赋值给另一个构造函 数的原型实现的。这样,子类型就能够访问超类型的所有属性和方法,这一点与基于类的继承很相似。 原型链的问题是对象实例共享所有继承的属性和方法,因此不适宜单独使用。解决这个问题的技术是借 用构造函数,即在子类型构造函数的内部调用超类型构造函数。这样就可以做到每个实例都具有自己的 属性,同时还能保证只使用构造函数模式来定义类型。使用最多的继承模式是组合继承,这种模式使用 原型链继承共享的属性和方法,而通过借用构造函数继承实例属性。 此外,还存在下列可供选择的继承模式。 4 原型式继承,可以在不必预先定义构造函数的情况下实现继承,其本质是执行对给定对象的浅 复制。而复制得到的副本还可以得到进一步改造。 5 寄生式继承,与原型式继承非常相似,也是基于某个对象或某些信息创建一个对象,然后增强 对象,最后返回对象。为了解决组合继承模式由于多次调用超类型构造函数而导致的低效率问 题,可以将这个模式与组合继承一起使用。 6 寄生组合式继承,集寄生式继承和组合继承的优点与一身,是实现基于类型继承的最有效方式。